/*
** Copyright (c) 2010 by Lorimark Solutions, LLC.
** All Rights Reserved.
** Send inquiries to: info@lorimarksolutions.com
**
*/

/*************************************************************************/
/*************************************************************************/
/*************************************************************************/

#include <evie-systems.h>
#include <font3x5.h>
#include <font10x16.h>
#include <avr/pgmspace.h>

/*
** fuses:
**  lfuse = 0xe6
**  hfuse = 0xd7
**
*/

/*

    00000000000000001111111111111111222222222222222233333333333333334444444444444444555555555555555566666666666666667777777777777777
    0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
   +--------------------------------------------------------------------------------------------------------------------------------+
000| ****    **    ****   ****  **  ** ******  ****  ******  ****   ****       ****  **  **                                         |
 01|******  ***   ****** ****** **  ** ****** ****** ****** ****** ******     ****** **  **                                         |
 02|**  **   **       **     ** **  ** **     **         ** **  ** **  **     **  ** **  **                                         |
 03|**  **   **    *****   ***  ****** *****  *****     **   ****  ******     ****** **  **                                         |
 04|**  **   **   *****    ***   ***** ****** ******    **   ****   *****     ****** **  **                                         |
 05|**  **   **   **         **     **     ** **  **    **  **  **     **  *  **  ** **  **                                         |
 06|****** ****** ****** ******     ** ****** ******    **  ******     ** *** **  **  ****                                          |
 07| ****  ******  ****   ****      **  ****   ****     **   ****      **  *  **  **   **                                           |
108|                                                                                                                                |
 09|                                                                                                                                |
 0A|                                                                                                                                |
 0B|                                                                                                                                |
 0C|                                                                                                                                |
 0D|                                                                                                                                |
 0E|                                                                                                                                |
 0F|                                                                                                                                |
210|
 11|
 12| *  *** *** *   *** *** *** *** ***
 13|**    *   * * * *   *     * * * * *
 14| *  ***  ** *** *** ***   *  *  ***
 15| *  *     *   *   * * *   * * *   *
 16|*** *** ***   * *** ***   * ***   *
 17|******************************************************************************************************************************* |
318|                                                                                                                                |
 19|***                                                             *** ***                                     *** *** *** *** *** |
 1A|*** ***                                 ***             *** *** *** *** ***                 *** *** *** *** *** *** *** *** *** |
 1B|*** *** *** *** ***         *** *** *** *** ***         *** *** *** *** *** ***         *** *** *** *** *** *** *** *** *** *** |
 1C|*** *** *** *** ***         *** *** *** *** ***     *** *** *** *** *** *** ***         *** *** *** *** *** *** *** *** *** *** |
 1D|*** *** *** *** *** ***     *** *** *** *** ***     *** *** *** *** *** *** ***     *** *** *** *** *** *** *** *** *** *** *** |
 1E|*** *** *** *** *** ***     *** *** *** *** ***     *** *** *** *** *** *** ***     *** *** *** *** *** *** *** *** *** *** *** |
 1F|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***     *** *** *** *** *** *** *** *** *** *** *** |
420|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 21|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 22|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 23|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 24|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 25|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 26|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 27|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
528|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 29|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 2A|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 2B|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 2C|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 2D|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 2E|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 2F|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
630|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 31|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 32|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 33|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 34|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 35|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 36|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 37|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
738|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 39|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 3A|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 3B|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 3C|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 3D|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 3E|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
 3F|*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
   +--------------------------------------------------------------------------------------------------------------------------------+
    00000000000000001111111111111111222222222222222233333333333333334444444444444444555555555555555566666666666666667777777777777777
    0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF

    00000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111
     0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1
     0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F

*/



#define SET(p,b)  p  |=  (b)
#define CLR(p,b)  p  &= ~(b)
#define TST(p,b)  (p &   (b))

#define LCD_DELAY_500  asm volatile ("nop"); \
  asm volatile ("nop"); \
  asm volatile ("nop"); \
  asm volatile ("nop"); \
  asm volatile ("nop"); \
  asm volatile ("nop"); \
  asm volatile ("nop"); \
  asm volatile ("nop");

#define HARDWARE_REV_F

#ifdef HARDWARE_REV_D
#define LCD_DELAY        1
#define LCD_DATA_DDR     DDRA
#define LCD_DATA_OUT     PORTA
#define LCD_DATA_PIN     PINA
#define LCD_CONTROL_DDR  DDRB
#define LCD_CONTROL_OUT  PORTB
#define LCD_CONTROL_PIN  PINB
#define LCD_RESET_DDR    DDRC
#define LCD_RESET_OUT    PORTC
#define LCD_RESET_PIN    PINC
#define LCD_RST_BIT      (1<<PC7)
#define LCD_CS2_BIT      (1<<PB1)
#define LCD_CS1_BIT      (1<<PB0)
#define LCD_E_BIT        (1<<PB2)
#define LCD_RW_BIT       (1<<PB3)
#define LCD_DI_BIT       (1<<PB4)
#endif

#ifdef HARDWARE_REV_E
#define LCD_DELAY        1
#define LCD_DATA_DDR     DDRA
#define LCD_DATA_OUT     PORTA
#define LCD_DATA_PIN     PINA
#define LCD_CONTROL_DDR  DDRB
#define LCD_CONTROL_OUT  PORTB
#define LCD_CONTROL_PIN  PINB
#define LCD_RESET_DDR    DDRC
#define LCD_RESET_OUT    PORTC
#define LCD_RESET_PIN    PINC
#define LCD_RST_BIT      (1<<PC5)
#define LCD_CS2_BIT      (1<<PC6)
#define LCD_CS1_BIT      (1<<PC7)
#define LCD_E_BIT        (1<<PB0)
#define LCD_RW_BIT       (1<<PB1)
#define LCD_DI_BIT       (1<<PB2)
#endif

#ifdef HARDWARE_REV_F
#define LCD_DELAY        1
#define LCD_DATA_DDR     DDRA
#define LCD_DATA_OUT     PORTA
#define LCD_DATA_PIN     PINA
#define LCD_CONTROL_DDR  DDRB
#define LCD_CONTROL_OUT  PORTB
#define LCD_CONTROL_PIN  PINB
#define LCD_RESET_DDR    DDRC
#define LCD_RESET_OUT    PORTC
#define LCD_RESET_PIN    PINC
#define LCD_RST_BIT      (1<<PC5)
#define LCD_CS2_BIT      (1<<PC6)
#define LCD_CS1_BIT      (1<<PC7)
#define LCD_E_BIT        (1<<PB0)
#define LCD_RW_BIT       (1<<PB1)
#define LCD_DI_BIT       (1<<PB2)
#endif

uint8 chip_lcd;
uint8 segment_lcd;

void delay_lcd(void)
{
  _delay_us(5);
}

/*!
** \brief Select a Chip
**
** Since most everything is zero-based in C and in nearly
**  all other systems, I have written this chip selector
**  to be zero-based also.  Sending a chip==0 selects the
**  first chip, sending a chip==1 selects the second chip.
**  Sending anything else selects no chip.
**
**
*/
void chipSelect_lcd( uint8 chip )
{
  /*
  ** Bring the enable pin low
  **
  */
  LCD_CONTROL_OUT &= ~LCD_E_BIT;

  /*
  ** Wait a bit before doing anything.
  **
  */
  delay_lcd();

  /*
  ** If the chip has not changed, then we 
  **  can quit early.
  **
  */
  if( chip_lcd == chip )
  {
    return;
  }

  /*
  ** Remember the chip for next time.
  **
  */
  chip_lcd = chip;

  LCD_RESET_DDR |= (LCD_CS1_BIT + LCD_CS2_BIT);
  
  /*
  ** Set the chip selects.  Note that the chip selects
  **  will not change if the chip itself has not changed.
  **
  */
  switch( chip_lcd )
  {
    case 0:
    {
      #ifdef HARDWARE_REV_D
      LCD_CONTROL_OUT &= ~LCD_CS2_BIT;
      LCD_CONTROL_OUT |=  LCD_CS1_BIT;
      #endif
      #ifdef HARDWARE_REV_E
      LCD_RESET_OUT &= ~LCD_CS2_BIT;
      LCD_RESET_OUT |=  LCD_CS1_BIT;
      #endif
      #ifdef HARDWARE_REV_F
      LCD_RESET_OUT &= ~LCD_CS2_BIT;
      LCD_RESET_OUT |=  LCD_CS1_BIT;
      #endif
      break;
    }

    case 1:
    {
      #ifdef HARDWARE_REV_D
      LCD_CONTROL_OUT &= ~LCD_CS1_BIT;
      LCD_CONTROL_OUT |=  LCD_CS2_BIT;
      #endif
      #ifdef HARDWARE_REV_E
      LCD_RESET_OUT &= ~LCD_CS1_BIT;
      LCD_RESET_OUT |=  LCD_CS2_BIT;
      #endif
      #ifdef HARDWARE_REV_F
      LCD_RESET_OUT &= ~LCD_CS1_BIT;
      LCD_RESET_OUT |=  LCD_CS2_BIT;
      #endif
      break;
    }
  }

  delay_lcd();
}

// Purpose:       Reads a byte of data from the specified chip
// Ouputs:        A byte of data read from the chip
uint8 readByte_lcd(void)
{
  /*
  ** temp holders for the data from the lcd
  **
  */
  uint8 data;

  /*
  ** Make sure the read/write is READ.
  **
  */
  LCD_CONTROL_OUT |= LCD_RW_BIT;

  /*
  ** Make the data port an input
  **
  */
  LCD_DATA_DDR = 0x00;

  /*
  ** Pulsate the enable line
  **
  */
  LCD_CONTROL_OUT |=  LCD_E_BIT; delay_lcd();
  LCD_CONTROL_OUT &= ~LCD_E_BIT; delay_lcd();
  LCD_CONTROL_OUT |=  LCD_E_BIT; delay_lcd();

  /*
  ** Acquire the data
  **
  */
  data = LCD_DATA_PIN;

  /*
  ** Release the enable (disable the device)
  **
  */
  LCD_CONTROL_OUT &= ~LCD_E_BIT;

  /*
  ** Return the read data
  **
  **
  */
  return( data );

}

uint8 readStatus_lcd(void)
{
  LCD_CONTROL_OUT &= ~LCD_DI_BIT;

  return( readByte_lcd() );
}

void wait_lcd( uint8 dataInstruction )
{
  while( (readStatus_lcd() & 0x80) );

  if( dataInstruction == 1 )
  {
    LCD_CONTROL_OUT |= LCD_DI_BIT;
  }
}

// Purpose:       Write a byte of data to the specified chip
// Inputs:        chipSelect - which chip to write the data to
//                data - the byte of data to write
void writeByte_lcd( uint8 data )
{
  /*
  ** Set the data bus pins as output
  **
  */
  LCD_DATA_DDR = 0xff;

  /*
  ** Set for writing
  **
  */
  LCD_CONTROL_OUT &= ~LCD_RW_BIT;

  /*
  ** Set the data on the port
  **
  */
  LCD_DATA_OUT = data;

  /*
  ** Pulse the enable pin
  **
  */
  delay_lcd(); LCD_CONTROL_OUT |=  LCD_E_BIT;
  delay_lcd(); LCD_CONTROL_OUT &= ~LCD_E_BIT;

}

void segmentSelect_lcd( uint16 segmentNumber )
{
  /*
  ** Determine the chip number.  This is determined by bit 6 of.
  **  the segment number.  If this bit is ever true, then we 
  **  know we are addressing the second chip, otherwise we are 
  **  addressing the first chip.
  **
  */
  if( segmentNumber & 0x40 )
  {
    chipSelect_lcd(1);
  }
  else
  {
    chipSelect_lcd(0);
  }

}

void address_lcd( uint16 segmentNumber )
{
  segmentSelect_lcd( segmentNumber );

  /*
  ** Write the segment address.  This is the segment number
  **  0..63, or the 'Y' address according to the documentation.
  **  From the 'segmentNumber', it is bits 5..0 or 0x3f.  The
  **  command for writing the Y address is 0x40, to which we 
  **  then encode the actual segment value.
  **
  */
  wait_lcd(0);
  writeByte_lcd( 0x40 | (segmentNumber & 0b00111111) );

  /*
  ** Write the page address.  This is the page number 0..7 that
  **  occurs in bits 9..7 of the 'segmentNumber'.  We can get
  **  to them easily enough by masking and shifting.  The
  **  command for writing the page address is 0xb8, to 
  **  which we then encode the actual page value.
  **
  */
  wait_lcd(0);
  writeByte_lcd( 0xb8 | ((segmentNumber >> 7) & 0b00000111) );

  wait_lcd(1);

}

uint8 readSegment_lcd( uint16 segmentNumber )
{
  /*
  ** Address the lcd so that we're reading the correct data.
  **
  */
  address_lcd( segmentNumber );

  /*
  ** Read the data at that location
  **
  */
  return( readByte_lcd() );

}

void writeSegment_lcd( uint16 segmentNumber, uint8 dataByte )
{
  /*
  ** Address the lcd so that we're reading the correct data.
  **
  */
  address_lcd( segmentNumber );

  /*
  ** Write the data to that location
  **
  */
  writeByte_lcd( dataByte );

}

// Purpose: // Purpose:       Fill the LCD screen with the passed in color.
//                Works much faster than drawing a rectangle to fill the screen.
// Inputs:        ON - turn all the pixels on
//                OFF - turn all the pixels off
// Dependencies:  glcd_writeByte()
void fillScreen_lcd( uint8 fillByte )
{
  uint16 i, j;

  for( i = 0; i < 1024; i += 64 )
  {
    wait_lcd(0);
    writeSegment_lcd( i, fillByte );

    // Loop through the vertical pages
    for( j = 1; j < 64; j++ )
    {
      wait_lcd(1);
      writeByte_lcd( fillByte );
    }

  }
  
}







/*************************************************************************/
/*************************************************************************/
/*************************************************************************/


const uint8 characters[] PROGMEM =
{
  0b00001110, // 0
  0b00010001,
  0b00001110,
  0b00000000,

  0b00010010, // 1
  0b00011111,
  0b00010000,
  0b00000000,

  0b00011101, // 2
  0b00010101,
  0b00010111,
  0b00000000,

  0b00010001, // 3
  0b00010101,
  0b00011111,
  0b00000000,

  0b00000111, // 4
  0b00000100,
  0b00011111,
  0b00000000,

  0b00010111, // 5
  0b00010101,
  0b00011101,
  0b00000000,

  0b00011111, // 6
  0b00010101,
  0b00011101,
  0b00000000,

  0b00000001, // 7
  0b00000001,
  0b00011111,
  0b00000000,

  0b00011111, // 8
  0b00010101,
  0b00011111,
  0b00000000,

  0b00000111, // 9
  0b00000101,
  0b00011111,
  0b00000000,

  0b00011110, // A
  0b00000101,
  0b00011110,
  0b00000000,

  0b00011111, // B
  0b00010100,
  0b00001000,
  0b00000000,

  0b00011111, // C
  0b00010001,
  0b00010001,
  0b00000000,

  0b00001000, // D
  0b00010100,
  0b00011111,
  0b00000000,

  0b00011111, // E
  0b00010101,
  0b00010001,
  0b00000000,

  0b00011111, // F
  0b00000101,
  0b00000001,
  0b00000000,

  0b00001010,
  0b00000100,
  0b00001010,
  0b00000000,

  0b00000100, // -
  0b00000100,
  0b00000100,
  0b00000000
};


uint16 segment;

void writeCharacter_lcd( uint8 character )
{
  if( character > 0x0F ) character = 0x10;

  character *= 4;

  writeSegment_lcd( segment, pgm_read_byte( &characters[character++] ) );
  writeByte_lcd(             pgm_read_byte( &characters[character++] ) );
  writeByte_lcd(             pgm_read_byte( &characters[character++] ) );
  writeByte_lcd(             pgm_read_byte( &characters[character]   ) );

  segment += 4;
}

void writeDecNumber_lcd( uint16 startingSegment, uint16 number, uint16 divisor )
{
  uint8  x = 0;

  segment = startingSegment;

  while( divisor > 0 )
  {
    x = 0;
    while( number >= divisor )
    {
      x++;
      number -= divisor;
    }

    writeCharacter_lcd( x );

    divisor /= 10;

  }

}

void writeDecNumberVert_lcd( uint16 startingSegment, uint16 number, uint16 divisor )
{
  uint8  x = 0;
  uint8  y = 0;

  while( divisor > 0 )
  {
    x = 0;
    while( number >= divisor )
    {
      x++;
      number -= divisor;
    }

    segment = startingSegment + (128 * y++);

    writeCharacter_lcd( x );

    divisor /= 10;

  }

}

void writeHexNumber_lcd( uint16 startingSegment, uint16 number )
{
  uint8  x = 0;
  uint16 y = 0x1000;

  if( startingSegment == 0xffff )
  {
    segment += 4;
  }
  else
  {
    segment = startingSegment;
  }

  while( y > 0 )
  {
    x = 0;
    while( number >= y )
    {
      x++;
      number -= y;
    }

    writeCharacter_lcd( x );

    y >>= 4;

  }
}

/*************************************************************************/
/*************************************************************************/
/*************************************************************************/

/*
    000000000000000011111111111111112222222222222222333333333333333344444
    0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF01234
   +---------------------------------------------------------------------
000| ****    **    ****   ****  **  ** ******  ****  ******  ****   **** 
 01|******  ***   ****** ****** **  ** ****** ****** ****** ****** ******
 02|**  **   **       **     ** **  ** **     **         ** **  ** **  **
 03|**  **   **    *****   ***  ****** *****  *****     **   ****  ******
 04|**  **   **   *****    ***   ***** ****** ******    **   ****   *****
 05|**  **   **   **         **     **     ** **  **    **  **  **     **
 06|****** ****** ****** ******     ** ****** ******    **  ******     **
 07| ****  ******  ****   ****      **  ****   ****     **   ****      **

*/

const uint8 big_characters[] PROGMEM =
{
  0b01111110, // 0
  0b11111111,
  0b11000011,
  0b11000011,
  0b11111111,
  0b01111110,


  0b11000000, // 1
  0b11000010,
  0b11111111,
  0b11111111,
  0b11000000,
  0b11000000,


  0b01110010, // 2
  0b11111011,
  0b11011011,
  0b11011011,
  0b11011111,
  0b01001110,


  0b01000010, // 3
  0b11000011,
  0b11011011,
  0b11011011,
  0b11111111,
  0b01100110,


  0b00001111, // 4
  0b00011111,
  0b00011000,
  0b00011000,
  0b11111111,
  0b11111111,


  0b01011111, // 5
  0b11011111,
  0b11011011,
  0b11011011,
  0b11111011,
  0b01110011,


  0b01111110, // 6
  0b11111111,
  0b11011011,
  0b11011011,
  0b11111011,
  0b01110010,


  0b00000011, // 7
  0b00000011,
  0b00000011,
  0b11111011,
  0b11111111,
  0b00000111,


  0b01100110, // 8
  0b11111111,
  0b11011011,
  0b11011011,
  0b11111111,
  0b01100110,


  0b00001110, // 9
  0b00011111,
  0b00011011,
  0b00011011,
  0b11111111,
  0b11111110,


  0b11111100, // A
  0b11111110,
  0b00011011,
  0b00011011,
  0b11111110,
  0b11111100,


  0b00000000, // B
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,


  0b00000000, // C
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,


  0b00000000, // D
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,


  0b00000000, // E
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,


  0b00000000, // F
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,


  0b00111111, // V
  0b01111111, // 0x10
  0b11100000,
  0b11100000,
  0b01111111,
  0b00111111,


  0b00000110, // ?
  0b00000110, // 0x11
  0b11010011,
  0b11011011,
  0b00001110,
  0b00000110,


};


void writeBigDecimal_lcd(void)
{
  writeSegment_lcd( segment, 0b01000000 );
  writeByte_lcd(             0b11100000 );
  writeByte_lcd(             0b01000000 );
  writeByte_lcd(             0b00000000 );
  segment += 4;
}

void writeBigCharacter_lcd( uint8 character )
{
  uint8 i;

  if( character == 'V' ) character = 0x10;
  if( character == 'A' ) character = 0x0a;
  if( character == '?' ) character = 0x11;
  if( character > 0x11 ) character = 0x11;

  character *= 6;

  for( i=0; i<6; i++, segment++, character++ )
  {
    writeSegment_lcd( segment, 	pgm_read_byte( &big_characters[character] ) );
  }

  writeSegment_lcd( segment++, 0 );

}


void writeBigDecNumber_lcd
( 
  uint16 startingSegment, 
  uint16 number, 
  uint16 divisor, 
  uint8  decimal
)
{
  uint8  x = 0;

  segment = startingSegment;

  while( divisor > 0 )
  {
    x = 0;
    while( number >= divisor )
    {
      x++;
      number -= divisor;
    }

    if( !decimal-- )
    {
      writeBigDecimal_lcd();
    }

    writeBigCharacter_lcd( x );

    divisor /= 10;

  }

}



/*************************************************************************/
/*************************************************************************/
/*************************************************************************/


void writeHugeDecimal_lcd(void)
{
  writeSegment_lcd( segment,     0b00000000 );
  writeByte_lcd(                 0b00000000 );
  writeByte_lcd(                 0b00000000 );
  writeByte_lcd(                 0b00000000 );
  writeSegment_lcd( segment+128, 0b00110000 );
  writeByte_lcd(                 0b01111000 );
  writeByte_lcd(                 0b00110000 );
  writeByte_lcd(                 0b00000000 );
  segment += 4;
}

void writeHugeMinus_lcd(void)
{
  writeSegment_lcd( segment,     0b10000000 );
  writeByte_lcd(                 0b10000000 );
  writeByte_lcd(                 0b10000000 );
  writeByte_lcd(                 0b00000000 );
  writeSegment_lcd( segment+128, 0b00000001 );
  writeByte_lcd(                 0b00000001 );
  writeByte_lcd(                 0b00000001 );
  writeByte_lcd(                 0b00000000 );
  segment += 4;
}

void writeHugePlus_lcd(void)
{
  writeSegment_lcd( segment,     0b10000000 );
  writeByte_lcd(                 0b11000000 );
  writeByte_lcd(                 0b10000000 );
  writeByte_lcd(                 0b00000000 );
  writeSegment_lcd( segment+128, 0b00000001 );
  writeByte_lcd(                 0b00000011 );
  writeByte_lcd(                 0b00000001 );
  writeByte_lcd(                 0b00000000 );
  segment += 4;
}

void writeHugeCharacter_lcd( uint8 character )
{
  uint8  i;

  if( character == 'A' ) character = 0x0a;
  if( character == 'V' ) character = 0x0b;
  if( character == 'T' ) character = 0x0c;
  if( character == 'F' ) character = 0x0d;
  if( character == '-' ) character = 0x0e;
//  if( character == '?' ) character = 0x11;
  if( character > 0x11 ) character = 0x11;

  character *= 10;

  for( i=0; i<10; i++, segment++, character++ )
  {
    writeSegment_lcd( segment,     pgm_read_word( &font10x16[character] )      );
    writeSegment_lcd( segment+128, pgm_read_word( &font10x16[character] ) >> 8 );
  }

  writeSegment_lcd( segment,     0 );
  writeSegment_lcd( segment+128, 0 );
  segment++;

}


void writeHugeDecNumber_lcd
( 
  uint16 startingSegment, 
  sint16 number, 
  uint16 divisor, 
  uint8  decimal
)
{
  uint8  x = 0;

  segment = startingSegment;

  if( number < 0 )
  {
    writeHugeMinus_lcd();
    number *= -1;
  }
  else
  {
    writeHugePlus_lcd();
  }

  while( divisor > 0 )
  {
    x = 0;
    while( number >= divisor )
    {
      x++;
      number -= divisor;
    }

    if( !decimal-- )
    {
      writeHugeDecimal_lcd();
    }

    writeHugeCharacter_lcd( x );

    divisor /= 10;

  }

}











/*************************************************************************/
/*************************************************************************/
/*************************************************************************/






uint8 lcd_x; // 0..127
uint8 lcd_y; // 0..63

void add_lcd_x( unsigned char x, unsigned char y )
{

  lcd_x += x;
  if( lcd_x > 127 )
  {
    lcd_x  = 0;
    lcd_y += y;
    if( lcd_y > 63 )
    {
      lcd_y = 0;
    }
  }

}

void set_lcd_x( unsigned char x, unsigned char y )
{
  lcd_x = x;
  lcd_y = y;
}

//      Initialize a graphic LCD. This must be called before any
//                other glcd function is used.
// Inputs:        The initialization mode
//                OFF - Turns the LCD off
//                ON  - Turns the LCD on
// Date:          5/28/2003
void init_lcd( uint8 on )
{

  LCD_CONTROL_DDR |= 
    LCD_E_BIT   +
    LCD_RW_BIT  +
    LCD_DI_BIT  ;


  LCD_RESET_DDR |=
    LCD_CS2_BIT + 
    LCD_CS1_BIT +
    LCD_RST_BIT ;

  lcd_x = 0;
  lcd_y = 0;

  chip_lcd = -1;

  /*
  ** Issue a reset pulse
  **
  */
  LCD_RESET_OUT &= ~LCD_RST_BIT; _delay_ms(255);
  LCD_RESET_OUT |=  LCD_RST_BIT; _delay_ms(255);

  /*
  ** Send an instruction to turn the display on
  **
  */
  chipSelect_lcd(0); wait_lcd(0); writeByte_lcd( 0x3f );
                     wait_lcd(0); writeByte_lcd( 0xc0 );
  chipSelect_lcd(1); wait_lcd(0); writeByte_lcd( 0x3f );
                     wait_lcd(0); writeByte_lcd( 0xc0 );

  fillScreen_lcd(0x00);            // Clear the display

}


// Purpose:       Turn a pixel on a graphic LCD on or off
// Inputs:        x - the x coordinate of the pixel
//                y - the y coordinate of the pixel
//                color - ON or OFF
// Output:        1 if coordinate out of range, 0 if in range
void pixel_lcd( uint8 x, uint8 y, uint8 color )
{

  uint8 data;
  uint8 chip = 0;  // Stores which chip to use on the LCD

  x &= 0b01111111;
  y &= 0b00111111;

  if(x > 63)      // Check for first or second display area
  {
     x   -= 64;
     chip = 1;
  }

  chipSelect_lcd(chip);

  /*
  ** Set for instruction
  **
  */
  x &= 0b01111111;   // Clear the MSB. Part of an instruction code
  x |= 0b01000000;   // Set bit 6. Also part of an instruction code

  wait_lcd(0);
  writeByte_lcd( x );                                 // Set the horizontal address

  wait_lcd(0);
  writeByte_lcd( ((y/8) & 0b10111111) | 0b10111000 );   // Set the vertical page address

  /*
  ** read data
  **
  */
  wait_lcd(1);
  data = readByte_lcd();

//  printf( "x = %02x, chip = %u, data = %02x ", x, chip, data );

  if( color )
     data |=  (1<<(y%8));         // Turn the pixel on
  else                            // or
     data &= ~(1<<(y%8));         // turn the pixel off

//  printf( "data = %02x", data );

  wait_lcd(0);
  writeByte_lcd( x );      // Set the horizontal address

  wait_lcd(1);
  writeByte_lcd( data );   // Write the pixel data


}


// Purpose:       Write text on a graphic LCD
// Inputs:        (x,y) - The upper left coordinate of the first letter
//                textptr - A pointer to an array of text to display
//                size - The size of the text: 1 = 5x7, 2 = 10x14, ...
//                color - ON or OFF
void text35_lcd( uint8 x, uint8 y, uint8 c, uint8 color )
{
  uint8 i, j, k;
  uint16 inFont = 0;

//  printf( "\r\ntext35_lcd %u %u %c ", x, y, c );

  /*
  ** Make sure the letter is within range.  If it is we pull
  **  the actual font data from the array
  **
  */
  if( (c >= (' '-1)) && (c <= '~') )
  {
    inFont = pgm_read_word( &font3x5[c-(' '-1)] );
  }

//  printf( "if:%lx", inFont );

  for( i = 0, k = 0; i < 3; i++ )
  {
//    printf( "\r\n" );

    for( j = 0; j < 5; j++, k++ )
    {
//      printf( "%d", j );

      if( inFont & (1<<k) )
      {
//        printf( "*" );
        pixel_lcd( x+i, y+j, 1 );
      }
      else
      {
//        printf( " " );
        pixel_lcd( x+i, y+j, 0 );
      }
    }
  }


}

void putc_lcd( uint8 c )
{
//  printf( "\r\nputc_lcd %c", c );

  text35_lcd( lcd_x, lcd_y, c, 1 );

  add_lcd_x(4,6); // advance to the next character position

}

void puts_lcd( char * s )
{
  while( *s )
  {
    putc_lcd( *s++ );
  }
}

void putp_lcd( const char s[] )
{
  while( pgm_read_byte(s) )
  {
    putc_lcd( pgm_read_byte(s++) );
  }
}

